#include "Protocol.hpp"
#include "TcpServer.hpp"
#include "Socket.hpp"
#include "log.hpp"
#include "LockGuard.hpp"
#include "Calculate.hpp"

#include <iostream>
#include <string>
#include <functional>

using calculate_t = std::function<Response(Request &request)>;

class Service
{
public:
    Service(calculate_t cal)
        : _cal(cal)
    {
    }

    void service(mySocket::socket_ptr service, InetAddr clientAddr)
    {
        LOG(INFO, "[%s:%d] link success", clientAddr.IP().c_str(), clientAddr.Port());
        // 收消息

        std::string inbuffer;
        while (true)
        {
            int n = service->socketRecv(&inbuffer);
            if (n < 0)
            {
                LOG(INFO, "client[%s, %d] quit", clientAddr.IP(), clientAddr.Port());
                break;
            }
            while (true)
            {
                // 检验收到的消息是否完整
                //std::cout << "inbuffer: " << inbuffer << std::endl;
                std::string package = DeCode(inbuffer);
                if (package.empty())
                    break;

                std::cout << "package: " << package << std::endl;

                std::cout << "----------------begin-----------------" << std::endl;
                // 收到了完整的消息，将信息反序列化
                Request request;
                request.Deserialize(package);

                //printf("x = %d, y = %d, op = %c\n", request.getX(), request.getY(), request.getOption());

                // 执行任务
                Response response = _cal(request);
                //printf("res = %d, code = %d\n", response.getResult(),  response.getCode());

                // 序列化任务结果
                std::string server_result;
                response.Serialize(&server_result);

                //std::cout << "server_result: " << server_result << std::endl;

                // 对任务结果添加报头
                Encode(server_result);

                //std::cout << "server_result: " << server_result << std::endl;

                // 发送回应
                int n = service->socketSend(server_result);
                if (n < 0)
                {
                    LOG(ERROR, "send error");
                    break;
                }
            }
        }
    }

private:
    calculate_t _cal;
};

void Usage(char *argv[])
{
    printf("%s\n\t[Port]", argv[0]);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv);
        exit(1);
    }

    Calculate calculate;
    uint16_t port = std::stoi(argv[1]);
    Service service(std::bind(&Calculate::Execute, &calculate, std::placeholders::_1));
    server_task_t server_task = std::bind(&Service::service, &service, std::placeholders::_1, std::placeholders::_2);
    tcpServer server(port, server_task);

    server.serverLoop();

    return 0;
}